//
//  comBlueboxmoonPhoneiTunes.m
//  iTunesPlugin
//
//  Created by Daniel Hazelbaker on 4/4/09.
//  Copyright 2009 Blue Box Moon. All rights reserved.
//

#import "comBlueboxmoonPhoneiTunes.h"
#import "BMSnomPhone.h"


@implementation comBlueboxmoonPhoneiTunes


//
// Determine if iTunes is currently running.
//
- (BOOL)iTunesIsRunning
{
    ProcessSerialNumber psn = { 0, kNoProcess };
    CFStringRef		stringRef;
    BOOL		iTunes = NO;


    //
    // Walk the entire process tree.
    //
    while (!GetNextProcess(&psn)) {
	if (psn.lowLongOfPSN == kNoProcess)
	    break;

	CopyProcessName(&psn, &stringRef);
	if ([(NSString *)stringRef isEqual:@"iTunes"] == YES) {
	    iTunes = YES;
	    CFRelease(stringRef);
	    break;
	}
	CFRelease(stringRef);
    }

    return iTunes;
}


//
// Determine wether or not iTunes is currently playing.
//
- (BOOL)iTunesIsPlaying
{
    NSAppleEventDescriptor  *returnDescriptor;
    NSAppleScript	    *scriptObject;
    NSDictionary	    *errorDict = nil;
    NSString		    *state;
    NSData		    *data;


    //
    // Execute the applescript command to request iTunes status.
    //
    scriptObject = [[NSAppleScript alloc] initWithSource:@"tell application \"iTunes\" to get player state as string"];
    returnDescriptor = [scriptObject executeAndReturnError:&errorDict];
    [scriptObject release];

    //
    // Check valid return and then coerce it into a useful string.
    //
    if ([returnDescriptor descriptorType]) {
	returnDescriptor = [returnDescriptor coerceToDescriptorType:typeUTF8Text];
	data = [returnDescriptor data];
	state = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
	if ([state isEqual:@"playing"] == YES)
	    return YES;
    }

    return NO;
}


//
// Determine wether or not iTunes is currently muted.
//
- (BOOL)iTunesIsMuted
{
    NSAppleEventDescriptor  *returnDescriptor;
    NSAppleScript	    *scriptObject;
    NSDictionary	    *errorDict = nil;


    //
    // Execute the applescript command to request iTunes status.
    //
    scriptObject = [[NSAppleScript alloc] initWithSource:@"tell application \"iTunes\" to get mute"];
    returnDescriptor = [scriptObject executeAndReturnError:&errorDict];
    [scriptObject release];

    //
    // Check valid return and then coerce it into a useful string.
    //
    if ([returnDescriptor descriptorType]) {
	if ([returnDescriptor descriptorType] == typeTrue)
	    return YES;
    }

    return NO;
}


//
// Retrieves the current volume of iTunes.
//
- (int)iTunesVolume
{
    NSAppleEventDescriptor  *returnDescriptor;
    NSAppleScript	    *scriptObject;
    NSDictionary	    *errorDict = nil;
    NSData		    *data;


    //
    // Execute the applescript command to request iTunes status.
    //
    scriptObject = [[NSAppleScript alloc] initWithSource:@"tell application \"iTunes\" to get sound volume"];
    returnDescriptor = [scriptObject executeAndReturnError:&errorDict];
    [scriptObject release];

    //
    // Check valid return and then coerce it into a useful string.
    //
    if ([returnDescriptor descriptorType]) {
	data = [returnDescriptor data];
	return *(int *)[data bytes];
    }

    return NO;
}


//
// Start iTunes playing.
//
- (void)iTunesPlay
{
    NSAppleScript	*scriptObject;
    NSDictionary	*errorDict = nil;


    //
    // Execute the applescript command to request iTunes status.
    //
    scriptObject = [[NSAppleScript alloc] initWithSource:@"tell application \"iTunes\" to play"];
    [scriptObject executeAndReturnError:&errorDict];
    [scriptObject release];
}


//
// Pause iTunes playing.
//
- (void)iTunesPause
{
    NSAppleScript	*scriptObject;
    NSDictionary	*errorDict = nil;


    //
    // Execute the applescript command to request iTunes status.
    //
    scriptObject = [[NSAppleScript alloc] initWithSource:@"tell application \"iTunes\" to pause"];
    [scriptObject executeAndReturnError:&errorDict];
    [scriptObject release];
}


//
// Stop iTunes playing.
//
- (void)iTunesStop
{
    NSAppleScript	*scriptObject;
    NSDictionary	*errorDict = nil;


    //
    // Execute the applescript command to request iTunes status.
    //
    scriptObject = [[NSAppleScript alloc] initWithSource:@"tell application \"iTunes\" to stop"];
    [scriptObject executeAndReturnError:&errorDict];
    [scriptObject release];
}


//
// Mute iTunes.
//
- (void)iTunesMute
{
    NSAppleScript	*scriptObject;
    NSDictionary	*errorDict = nil;


    //
    // Execute the applescript command to request iTunes status.
    //
    scriptObject = [[NSAppleScript alloc] initWithSource:@"tell application \"iTunes\" to set mute to true"];
    [scriptObject executeAndReturnError:&errorDict];
    [scriptObject release];
}


//
// Unmute iTunes.
//
- (void)iTunesUnmute
{
    NSAppleScript	*scriptObject;
    NSDictionary	*errorDict = nil;


    //
    // Execute the applescript command to request iTunes status.
    //
    scriptObject = [[NSAppleScript alloc] initWithSource:@"tell application \"iTunes\" to set mute to false"];
    [scriptObject executeAndReturnError:&errorDict];
    [scriptObject release];
}


//
// Set the volume of iTunes playback.
//
- (void)iTunesVolume:(int)newVolume
{
    NSAppleScript	*scriptObject;
    NSDictionary	*errorDict = nil;


    //
    // Execute the applescript command to request iTunes status.
    //
    scriptObject = [[NSAppleScript alloc] initWithSource:[NSString stringWithFormat:@"tell application \"iTunes\" to set sound volume to %d", newVolume]];
    [scriptObject executeAndReturnError:&errorDict];
    [scriptObject release];
}


//
// Set the default preferences.
//
+ (void)setDefaultPreferences
{
    BMPreferences *dict = [BMSnomPhone preferences];


    if ([dict valueForKey:kiTunesPauseDuringCallKey] == nil)
	[dict setValue:[NSNumber numberWithBool:YES] forKey:kiTunesPauseDuringCallKey];

    if ([dict valueForKey:kiTunesReduceVolumeDuringCallKey] == nil)
	[dict setValue:[NSNumber numberWithBool:NO] forKey:kiTunesReduceVolumeDuringCallKey];

    if ([dict valueForKey:kiTunesTargetVolumeDuringCallKey] == nil)
	[dict setValue:[NSNumber numberWithInt:25] forKey:kiTunesTargetVolumeDuringCallKey];
}


//
// Timer to adjust the volume slowly.
//
- (void)volumeTimer:(NSTimer *)timer
{
    float   bit = [[timer userInfo] floatValue];


    currentVolume = (currentVolume + bit);
    if ((bit < 0.0f && currentVolume <= targetVolume) || (bit > 0.0f && currentVolume >= targetVolume)) {
	currentVolume = targetVolume;
	[volumeTimer invalidate];
	volumeTimer = nil;
    }

    [self iTunesVolume:(int)currentVolume];
}



#pragma mark BMPluginHandlerProtocol
//////////////////////////////////////////////////////////////////////////
//
// BMPluginHandlerProtocol
//
//////////////////////////////////////////////////////////////////////////


//
// Activate the handler. This allows the handler to prep any information
// it needs. This method may be called more than once.
//
- (void)activateHandler
{
    iTunesResume = NO;
    iTunesVolume = -1;
}


//
// Notification continues through all plugins until all plugins have been
// notified. The phoneNumber will never be nil while the person may be nil
// if no lookup found a match.
//
- (void)notifyIncomingCall:(SSCall *)call
{
    BMPreferences   *preferences = [BMSnomPhone preferences];
    
    
    //
    // If this is not the first call or iTunes is not running then ignore it.
    //
    if ([self iTunesIsRunning] == NO)
	return;

    //
    // If iTunes is playing then mark it for restart and pause it.
    //
    if ([[preferences valueForKey:kiTunesPauseDuringCallKey] boolValue] == YES) {
	iTunesResume = [self iTunesIsPlaying];
	if (iTunesResume == YES)
	    [self iTunesPause];
    }
    else if ([[preferences valueForKey:kiTunesReduceVolumeDuringCallKey] boolValue] == YES) {
	targetVolume = [[preferences valueForKey:kiTunesTargetVolumeDuringCallKey] intValue];
	iTunesVolume = [self iTunesVolume];
	if (iTunesVolume > targetVolume) {
	    currentVolume = iTunesVolume;
	    if (volumeTimer != nil)
		[volumeTimer invalidate];
	    volumeTimer = [NSTimer scheduledTimerWithTimeInterval:0.10f target:self selector:@selector(volumeTimer:) userInfo:[NSNumber numberWithFloat:-((iTunesVolume - targetVolume) / 10.0f)] repeats:YES];
	}
	else
	    iTunesVolume = -1;
    }
}


//
// Notification continues through all plugins until all plugins have been
// notified. The phoneNumber will never be nil while the person may be nil
// if no lookup found a match.
//
- (void)notifyOutgoingCall:(SSCall *)call
{
    [self notifyIncomingCall:call];
}


//
// Notification that the call has ended.
//
- (void)notifyCallEnded:(NSString *)callID
{
    //
    // If this is not the last call or iTunes is not running then ignore it.
    //
    if ([self iTunesIsRunning] == NO)
	return;

    //
    // If we should re-start iTunes, then do so.
    //
    if (iTunesResume == YES) {
	[self iTunesPlay];
	iTunesResume = NO;
    }
    else if (iTunesVolume != -1) {
	currentVolume = [self iTunesVolume];
	targetVolume = iTunesVolume;
	iTunesVolume = -1;

	if (currentVolume < targetVolume) {
	    if (volumeTimer != nil)
		[volumeTimer invalidate];
	    volumeTimer = [NSTimer scheduledTimerWithTimeInterval:0.10f target:self selector:@selector(volumeTimer:) userInfo:[NSNumber numberWithFloat:((targetVolume - currentVolume) / 10.0f)] repeats:YES];
	}
    }
}


@end
